package tt.dz.service.imp.sys;

import java.util.*;
import java.util.regex.Pattern;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import tt.dz.dao.ext.base.OmsStoreFileDao;
import tt.dz.dao.ext.system.OmsOperListDao;
import tt.dz.dao.ext.system.OmsOperationSpListDao;
import tt.dz.dao.ext.system.OmsOperRoleDao;
import tt.dz.dao.ext.system.OmsUrlListDao;
import tt.dz.entity.base.JsonCommon;
import tt.dz.entity.base.JsonForList;
import tt.dz.entity.base.OmsCommonParam;
import tt.dz.entity.base.OmsEntityEnum;
import tt.dz.entity.base.OmsStoreFile;
import tt.dz.entity.exception.BizException;
import tt.dz.entity.exception.OmsDaoException;
import tt.dz.entity.system.OmsOperList;
import tt.dz.entity.system.OmsOperationSpList;
import tt.dz.entity.system.OmsUrlList;
import tt.dz.service.imp.base.BaseService;
import tt.dz.service.sys.OperListService;
import tt.dz.tcp.rpc.ms.SystemMasterServerRpcClient;
import tt.dz.tcp.rpc.ms.client.entity.*;
import tt.dz.util.DzDigester;
import tt.dz.util.OmsConstant;
import tt.dz.util.OmsConstant.MsgCodeEnum;
import tt.dz.util.StringUtil;
import tt.dz.util.serialGenerater;
import tt.dz.tcp.rpc.ms.client.entity.MasterModifyOperRoleVO.MasterModifyOperRoleRetVO;
import tt.dz.tcp.rpc.ms.client.entity.MasterModifyOperInfoVO.MasterModifyOperInfoParamVO;
import tt.dz.tcp.rpc.ms.client.entity.MasterModifyOperInfoVO.MasterModifyOperInfoRetVO;

@Service(value = "operatorService")
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
public class OperatorServiceImpl extends BaseService implements OperListService
{
	private Log log = LogFactory.getLog(OperatorServiceImpl.class);

	private static final String defaultPassword = "123456";

	@Autowired
	private OmsOperListDao operatorDaoImpl;
	@Autowired
	private SystemMasterServerRpcClient systemMasterServerRpcClient;
	@Autowired
	private OmsOperRoleDao omsOperRoleDaoImpl;
	@Autowired
	private OmsUrlListDao omsUrlListDaoImpl;
	@Autowired
	private OmsOperationSpListDao omsOperationSpListDao;

	@Autowired
	private RedisTemplate<String, String> redisTemplate;
	@Autowired
	private OmsStoreFileDao<OmsStoreFile> storeFileDaoImpl;

	@Value("${cacheOutTime}")
	private long timeOut;
	@Value("${userAuthKey}")
	private String userAuthKey;//=oms_auth_src

	@Override
	public OmsOperList login(String login_id, String password) throws BizException
	{
        //oms单方面停止OMS系统操作权限
		OmsOperList omsOperQury = new OmsOperList(login_id);
		OmsOperList omsOper_by_account = operatorDaoImpl.findOneExample(omsOperQury, null, null);
		if (omsOper_by_account != null && !"1".equals(Integer.toString(omsOper_by_account.getValid_flag())) ){
			throw new BizException(MsgCodeEnum.ERROR400.getMsgCode(), "此账号被锁定");
		}
		
		MasterLoginParam loginParam = new MasterLoginParam(login_id, password);
		log.info("Login to server with userId : " + login_id);
		MasterLoginResult result = systemMasterServerRpcClient.systemLoginInteface(loginParam);
		if (result == null || result.getIsSuccess() != 1)
			throw new BizException(MsgCodeEnum.ERROR400.getMsgCode(), "您填写的帐号或密码不正确，请再次尝试");

		OmsOperList user = new OmsOperList();
		user.setMs_manager_id(result.getUserId());
		Date now = new Date();

		OmsOperList oper = null;
		try
		{
			OmsOperList omsOper_by_MsId = operatorDaoImpl.findOneExample(user, null, null);
			//OmsOperList omsOper_by_account = operatorDaoImpl.findOneExample(new OmsOperList(login_id), null, null);


			if (omsOper_by_MsId == null && omsOper_by_account == null)
			{
				//添加一个用户到oms
				user.setOper_id("MS" + serialGenerater.generateSerialNo());
				user.setAccount(login_id);
				user.setCreate_time(now);
				user.setLast_time(now);
				user.setAccount(login_id);
				user.setPassword(password);
				user.setOper_name(login_id);
				user.setUser_type("1");//操作员

				//					user.setStatus(1);
				user.setValid_flag(1);
				operatorDaoImpl.add(user);
				if (result.getRoleList() != null && result.getRoleList().size() > 0)
				{
					String[] list_roleids = new String[result.getRoleList().size()];
					for (int i = 0; i < result.getRoleList().size(); i++)
					{
						list_roleids[i] = result.getRoleList().get(i).getRoleId();
					}
					omsOperRoleDaoImpl.assignRolsToOper(user.getOper_id(), list_roleids);
				}
				oper = user;

			}
			else if (omsOper_by_MsId != null && omsOper_by_account == null)
			{
				//把omsOper_by_MsId 的 Ms_manager_id 置为null,再新增一个用户到oms
				omsOper_by_MsId.setMs_manager_id(null);
				operatorDaoImpl.update(omsOper_by_MsId);
				//添加一个用户到oms
				user.setOper_id("MS" + serialGenerater.generateSerialNo());
				user.setAccount(login_id);
				user.setCreate_time(now);
				user.setLast_time(now);
				user.setAccount(login_id);
				user.setPassword(password);
				user.setOper_name(login_id);
				user.setUser_type("1");//操作员
				//					user.setStatus(1);
				user.setValid_flag(1);
				operatorDaoImpl.add(user);
				if (result.getRoleList() != null && result.getRoleList().size() > 0)
				{
					String[] list_roleids = new String[result.getRoleList().size()];
					for (int i = 0; i < result.getRoleList().size(); i++)
					{
						list_roleids[i] = result.getRoleList().get(i).getRoleId();
					}
					omsOperRoleDaoImpl.assignRolsToOper(user.getOper_id(), list_roleids);
				}
				oper = user;
			}
			else if (omsOper_by_MsId == null && omsOper_by_account != null)
			{
				//update omsOper_by_account 中的 Ms_manager_id为最新查询MS得到的  Ms_manager_id
				omsOper_by_account.setMs_manager_id(result.getUserId());
				operatorDaoImpl.update(omsOper_by_account);
				oper = omsOper_by_account;
			}
			else if (omsOper_by_MsId != null && omsOper_by_account != null)
			{//数据库中account不能为空
				if (omsOper_by_MsId.getAccount().equals(login_id))
				{
					omsOper_by_MsId.setLast_time(now);
					operatorDaoImpl.update(omsOper_by_MsId);
					oper = omsOper_by_MsId;
				}
				else
				{//1.2 account不相等
					omsOper_by_MsId.setMs_manager_id(null);
					omsOper_by_account.setMs_manager_id(result.getUserId());
					operatorDaoImpl.update(omsOper_by_MsId);
					operatorDaoImpl.update(omsOper_by_account);
					oper = omsOper_by_account;
				}
			}

			if(oper != null)
			{
				oper.setIsSupper(0);
				if (oper.getEntity_type() != null && oper.getEntity_type() == 1 && StringUtils.isNotEmpty(oper.getEntity_id()))
				{//运营商
					//查询此用户是否是超级运营商所属的管理员
					OmsOperationSpList omsOperMerchant_query = new OmsOperationSpList();
					omsOperMerchant_query.setOper_merchant_id(oper.getEntity_id());
					OmsOperationSpList omsOperMerchant = omsOperationSpListDao.findOneExample(omsOperMerchant_query, null, null);
					if (omsOperMerchant != null)
						oper.setIsSupper(omsOperMerchant.getSuper_flag());
				}

				List<String> urls = new ArrayList<>();
				List<Pattern> urlPatterns = new ArrayList<>();
				StringBuffer sb = new StringBuffer();
				sb.append(" SELECT DISTINCT u.url_path ");
				sb.append(" FROM oms_oper_role r ");
				sb.append(" INNER JOIN oms_role_auth a ON r.role_id = a.role_id ");
				sb.append(" INNER JOIN oms_url_list u ON a.url_id = u.url_id ");
				sb.append(" WHERE r.valid_flag = 1 AND a.valid_flag = 1 AND u.valid_flag = 1  ");
				sb.append("   AND u.url_path IS NOT NULL AND r.oper_id = ? ");
				List<Map<String, Object>> list_urls = omsUrlListDaoImpl.findDataBySql(sb.toString(), oper.getOper_id());
				for(Map<String, Object> map : list_urls)
				{
					String url_path = (String)map.get("url_path");
					if(StringUtils.isNotEmpty(url_path))
					{
						urls.add(url_path);
						urlPatterns.add(Pattern.compile("^/[^/]+/?" + url_path + "/?[^/]*$"));
					}

				}
				oper.setPowerUrls(urls);
				oper.setUrlPatterns(urlPatterns);
			}

			return oper;
		}
		catch (Exception e)
		{
			log.error("login,find user error", e);
			throw new BizException(MsgCodeEnum.ERROR400.getMsgCode(), "system error", e);
		}
	}

	@Override
	public String add(OmsOperList oper) throws OmsDaoException
	{
		try
		{
			String operid = genarateLogicOperId(oper.getEntity_type());
			oper.setOper_id(operid);
			oper.setCreate_time(new Date());
			oper.setValid_flag(1);
			oper.setPassword(defaultPassword);
			oper.setPwdchg_ind(1);
			operatorDaoImpl.add(oper);
			return operid;
		}
		catch (OmsDaoException e)
		{
			log.error(e.getMessage(), e);
			throw e;
		}

	}

	@Override
	public void update(OmsOperList oper, OmsOperList current_user) throws Exception
	{
		try
		{
			//接口调用方，从业务角度说明Oper_id为必选参数：所以此处如果为空，应该返回失败
			if (StringUtils.isEmpty(oper.getOper_id()))
				throw new NullPointerException("Oper_id is empty");

			OmsOperList omsOperListTmp;
			OmsOperList param = new OmsOperList();
			param.setOper_id(oper.getOper_id());
			omsOperListTmp = operatorDaoImpl.findOneExample(param, null, null);

			if (omsOperListTmp == null)
				throw new BizException("Oper not found by given operid: " + oper.getOper_id());

			if (StringUtils.isNotEmpty(omsOperListTmp.getMs_manager_id()))
			{
				MasterModifyOperInfoParamVO paramVO = new MasterModifyOperInfoParamVO();
				paramVO.setOper(current_user.getMs_manager_id());
				paramVO.setSysCode(OmsConstant.sysCode);
				paramVO.setUserId(omsOperListTmp.getMs_manager_id());
				paramVO.setEmail(oper.getEmail());
				paramVO.setName(oper.getOper_name());
				paramVO.setMobileNo(oper.getAccount());
				MasterModifyOperInfoRetVO retVO = systemMasterServerRpcClient.modifyOperInfo(paramVO);
				if (retVO.getIsSuccess() != OmsConstant.Success)
					throw new BizException("Failed to update user to Main Server");
			}
			
			if (omsOperListTmp.getEntity_id() == null && oper.getEntity_id() != null)
			{
				//删除对应关系
				//operatorDaoImpl.logicDelOperStationByOperId(oper.getOper_id());
			}
			if (omsOperListTmp.getEntity_id() != null && oper.getEntity_id() == null)
			{
				//删除对应关系
				operatorDaoImpl.logicDelOperStationByOperId(oper.getOper_id());
			}
			if (omsOperListTmp.getEntity_id() != null && oper.getEntity_id() != null && !omsOperListTmp.getEntity_id().equals(oper.getEntity_id()))
			{
				//删除对应关系
				operatorDaoImpl.logicDelOperStationByOperId(oper.getOper_id());
			}
			if (omsOperListTmp.getAuth_range()!= null && oper.getAuth_range()!= null && omsOperListTmp.getAuth_range() == 1 && oper.getAuth_range() == 0)
			{
				//删除对应关系
				operatorDaoImpl.logicDelOperStationByOperId(oper.getOper_id());
			}

			operatorDaoImpl.update(oper);
		}
		catch (OmsDaoException e)
		{
			log.error(e.getMessage(), e);
			throw e;
		}
	}

	private String genarateLogicOperId(Integer entityType) throws OmsDaoException
	{
		String maxId = operatorDaoImpl.findMaxLogicOperId(entityType);
		StringBuilder maxsb = new StringBuilder();
		maxsb.append(entityType);
		maxsb.append("000");
		maxsb.append(genarateId(maxId, 13));
		return maxsb.toString();
	}

	@Override
	public JsonCommon<?> deleteLogical(String oper_id)
	{
		try
		{
			operatorDaoImpl.deleteById(oper_id, OmsOperList.class);
		}
		catch (Exception e)
		{
			this.logError("operator Service delete", e);
			return this.buildError400JsonCommon();
		}
		return this.buildSuccessJsonCommon("success");
	}

	@Override
	public List<OmsUrlList> getUrlListByOperId(String oper_id) throws OmsDaoException
	{
		try
		{
			List<OmsUrlList> lst = omsUrlListDaoImpl.findValidUrlListByManagerId(oper_id, 2);
			//			loopSubsUrls(lst, null);
			OmsUrlList menuVO = new OmsUrlList();
			menuVO.setUrl_id("root");
			recursiveMenu(menuVO, lst);
			removeChildren(lst);
			return lst;
		}
		catch (OmsDaoException e)
		{
			this.logError(e.getMessage(), e);
			throw e;
		}
	}

	public void getChildrenMenu(OmsUrlList menuVO, List<OmsUrlList> menuList)
	{
		Iterator<OmsUrlList> iterator = menuList.iterator();
		OmsUrlList sourceMenu = null;
		while (iterator.hasNext())
		{
			sourceMenu = iterator.next();
			if (sourceMenu.getPre_url_id().equals(menuVO.getUrl_id()))
			{
				sourceMenu.setPre_url_name((menuVO.getUrl_name()));
				menuVO.getSubUrls().add(sourceMenu);
			}
		}
	}

	public void recursiveMenu(OmsUrlList menuVO, List<OmsUrlList> menuList)
	{
		getChildrenMenu(menuVO, menuList);
		if (menuVO.getSubUrls().size() > 0)
		{
			Iterator<OmsUrlList> iterator = menuVO.getSubUrls().iterator();
			OmsUrlList sourceMenu = null;
			while (iterator.hasNext())
			{
				sourceMenu = iterator.next();
				recursiveMenu(sourceMenu, menuList);
			}
		}
	}

	public void removeChildren(List<OmsUrlList> menuList)
	{
		Iterator<OmsUrlList> iterator = menuList.iterator();
		while (iterator.hasNext())
		{
			if (!"root".equals(iterator.next().getPre_url_id()))
			{
				iterator.remove();
			}
		}
	}

	@Override
	public JsonForList<?> findPageObjs(OmsCommonParam param, OmsOperList oper, Integer entityType, String entityId)
	{
		try
		{
			List<OmsOperList> lst = null;
			int total = 0;
			if (entityType == OmsEntityEnum.SUPER_OPERMERCHANT.getValue())
			{
				lst = operatorDaoImpl.pagingFind(param, oper);
				if (param.isQueryTotal())
				{
					total = operatorDaoImpl.queryTotalByObject(oper);
				}
			}
			else if (entityType == OmsEntityEnum.OPERMERCHANT.getValue())
			{
				lst = operatorDaoImpl.findOpersByPMPageOrAll(entityId, param, oper);
				if (param.isQueryTotal())
				{
					total = operatorDaoImpl.findOpersCountByPM(entityId, param, oper);
				}
			}
			else if (entityType == OmsEntityEnum.OPRERMERCHANT_BRANCH.getValue())
			{
				lst = operatorDaoImpl.findOpersByPMBPageOrAll(entityId, param, oper);
				if (param.isQueryTotal())
				{
					total = operatorDaoImpl.findOpersCountByPMB(entityId, param, oper);
				}
			}
			else if (entityType == OmsEntityEnum.FACTORY.getValue())
			{
				lst = operatorDaoImpl.findOpersByFacPageOrAll(entityId, param, oper);
				if (param.isQueryTotal())
				{
					total = operatorDaoImpl.findOpersCountByFac(entityId, param, oper);
				}
			}

			return this.buildSuccessJsonForList(param, lst, total);
		}
		catch (Exception e)
		{
			this.logError(e.getMessage(), e);
			return this.buildError400JsonForList();
		}
	}

	@Override
	public Integer findIsSuperOperMerchant(String operId)
	{
		return omsOperationSpListDao.findUserIsSpuer(operId);
	}

	@Override
	public JsonCommon<?> findUserCanDoAction(String managerId, String accessPath)
	{
		List<String> urls = null;
		StringBuilder sbKey = new StringBuilder();
		try
		{
			sbKey.append(userAuthKey).append(":").append(managerId);
			this.setRedisTemplate(redisTemplate);
			urls = getRedisCache(sbKey.toString());
		}
		catch (Exception e)
		{
			this.logError(e.getMessage(), e);
		}
		if (urls == null)
		{
			try
			{
				urls = omsUrlListDaoImpl.findValidUrlListByManagerId(managerId);
			}
			catch (OmsDaoException e)
			{
				return this.buildOtherJsonCommon(MsgCodeEnum.SYSTEM_ERROR.getMsgCode(), MsgCodeEnum.SYSTEM_ERROR.getMsgInfo());
			}
			//写redis缓存也可以做成线程池，这样可以避免影响主程序继续运行
			try
			{
				addRedisCache(sbKey.toString(), urls, timeOut);
			}
			catch (Exception e)
			{
				//只记录不做操作。
				this.logError(e.getMessage(), e);
			}

		}

		for (String url : urls)
		{
			if (accessPath.contains(url))
			{
				return this.buildSuccessJsonCommon("success");
			}
		}
		return this.buildOtherJsonCommon(MsgCodeEnum.OL_NO_POWER_ACCESS_ERROR.getMsgCode(), MsgCodeEnum.OL_NO_POWER_ACCESS_ERROR.getMsgInfo());
	}

	@Override
	public JsonForList<?> findUserStoreFiles(OmsOperList omsOperList)
	{
		List<OmsStoreFile> files = null;
		if (omsOperList != null && omsOperList.getStoreFiles() == null)
		{
			OmsStoreFile storeFile = new OmsStoreFile();
			storeFile.setEntity_tbl("oms_oper_list");
			storeFile.setEntity_id(omsOperList.getMs_manager_id());
			try
			{
				files = storeFileDaoImpl.pagingFind(new OmsCommonParam(), storeFile);
			}
			catch (OmsDaoException e)
			{
				//				e.printStackTrace();
				this.logError(e.getMessage(), e);
			}
		}
		else
		{
			files = omsOperList.getStoreFiles();
		}
		omsOperList.setStoreFiles(files);
		return this.buildSuccessJsonForList(files);
	}

	@Override
	public void updatePwd(OmsOperList current_user, String oldPwd, String newPwd) throws BizException
	{
		MasterModifyPwdParam param = new MasterModifyPwdParam();
		param.setManagerId(current_user.getMs_manager_id());
		param.setPassword(oldPwd);
		param.setNewPassword(newPwd);
		param.setRepeatPassword(newPwd);
		MasterBaseReturn ret = systemMasterServerRpcClient.systemUserModifyPwdInteface(param);
		if (ret == null)
			throw new BizException("Unexpected error occur during modifying password");
		if (ret.getIsSuccess() == 0)
			throw new BizException(ret.getErrorCode(), ret.getErrorMsg());

		try
		{
			OmsOperList oper = operatorDaoImpl.findRecordByPK(current_user);
			oper.setPassword(newPwd);
			oper.setPwdchg_ind(0);
			operatorDaoImpl.update(oper);
		}
		catch (OmsDaoException e)
		{
			log.error(e.getMessage(), e);
			throw new BizException(e);
		}

	}

	@Override
	public void assignRolesToUser(String operId, String[] roleIds, OmsOperList current_user) throws Exception
	{
		OmsOperList oper_query = new OmsOperList();
		oper_query.setOper_id(operId);
		OmsOperList oper = operatorDaoImpl.findOneExample(oper_query, null, null);
		if (oper == null)
		{
			throw new BizException("Oper not found in Database by given oper_id: (" + operId + ")");
		}
		oper.setRoleId(roleIds);

		try
		{
			boolean invoke_masterserver_success = false;
			if (StringUtil.isBlank(oper.getMs_manager_id()))
			{
				MasterAddUserParam masterAddUserParam = new MasterAddUserParam();

				masterAddUserParam.setSysCode(OmsConstant.sysCode);
				masterAddUserParam.setCreatedBy(oper.getCreate_ms_user_id());
				masterAddUserParam.setRoleList(oper.getRoleId());
				masterAddUserParam.setName(oper.getOper_name());
				masterAddUserParam.setMobileNo(oper.getAccount());
				masterAddUserParam.setPassword(DzDigester.desEncrypt(oper.getPassword(), "QDFJzpvOtXk="));
				masterAddUserParam.setEmail(oper.getEmail());

				MasterAddUserReturn ret = systemMasterServerRpcClient.addSysUser(masterAddUserParam);
				invoke_masterserver_success = ret != null && ret.getIsSuccess() == OmsConstant.Success;
				if (!invoke_masterserver_success)
					throw new BizException("Failed to add user to Main Server, error message is: " + ret.getErrorMsg());
				oper.setMs_manager_id(ret.getUserId());
				operatorDaoImpl.update(oper);
			}
			else
			{
				MasterModifyOperRoleVO.MasterModifyOperRoleParamVO paramVO = new MasterModifyOperRoleVO.MasterModifyOperRoleParamVO();
				paramVO.setUserId(oper.getMs_manager_id());
				paramVO.setSysCode(OmsConstant.sysCode);
				paramVO.setOper(current_user.getMs_manager_id());
				paramVO.setRoleIdList(roleIds);
				MasterModifyOperRoleRetVO ret = systemMasterServerRpcClient.modifyOperRole(paramVO);
				invoke_masterserver_success = ret != null && ret.getIsSuccess() == OmsConstant.Success;
				if (!invoke_masterserver_success)
					throw new BizException("Failed to update operator role to Main Server, error message is: " + ret.getErrorMsg());

			}
			if (invoke_masterserver_success)
			{
				omsOperRoleDaoImpl.deleteOperRoleIds(operId);
				omsOperRoleDaoImpl.assignRolsToOper(operId, roleIds);
			}

		}
		catch (Exception e)
		{
			log.error(e.getMessage(), e);
			throw e;
		}
	}

	@Override
	public synchronized JsonCommon<?> getCurrentLoginUser(OmsOperList omsOperList, String loginSuperFlag)
	{
		Map<String, Object> pojo = new HashMap<>();
		pojo.put("currentLoginUser", omsOperList);
		pojo.put("loginSuperFlag", loginSuperFlag);
		return buildSuccessJsonCommon(pojo);
	}

	@Override
	public OmsOperList simpleLogin(String account, String password) {
		OmsOperList omsOperQuery = new OmsOperList(account);
		omsOperQuery.setPassword(password);
		OmsOperList oper = operatorDaoImpl.findOneExample(omsOperQuery, null, null);
		return oper;
	}

	@Override
	public OmsOperList getOper(String account) {
		OmsOperList omsOperQuery = new OmsOperList(account);
		OmsOperList oper = operatorDaoImpl.findOneExample(omsOperQuery, null, null);
		return oper;
	}
	
}
